
#include <string>

#include "ParserUtil.h"

static int variableCount = 333;     
EventEntry *any, *other;
extern int yylineno;
int yycolumnno;
int current_temp = 0;
int current_label = 0;
int current_state = 0;
extern string curState;

static void 
errPrint(ErrorST code, const string& sym) {
  switch (code) {
  case DUPLICATE_SYM:
	errMsgLn("Redefinition of name " + sym);
	break;
  case SYM_NOT_PRESENT:
	errMsgLn("Undeclared symbol `" + sym + "'");
	break;
  case INVALID_SCOPE:
	errMsgLn("Definition of `" + sym +"' is invalid in " + 
		   stm.currentScope()->name());
	break;
  default:
	break;
  }
}

ErrorST insertSymbolErrCheck(SymTabEntry* se) {
  ErrorST err = stm.insert(se);
  errPrint(err, se->name());
  return err;
}

void enterScopeErrCheck(SymTabEntry* se) {
  errPrint(stm.enterScope(se), se->name());
}

string newName(const string& type) {
  string s("__");
  s +=type+"__"+ itoa(variableCount++);
  return s;
}

string itoa(int i) {
  char a[20];
  sprintf(a, "%d", i);
  return string(a);
}

string gen_temp()
{
	string temp;
	temp = "t";
	temp += itoa(current_temp++);
	return temp;
}


//william
string newLabel()
{
    string temp;
    temp = "Lab";
    temp += itoa(current_label++);
    return temp;
}

string newLabel(string str)
{
    string temp;
    temp = "Lab";
    temp += itoa(current_label++);
    return temp + str;
}

string newState() {
    string temp;
    temp = "State";
    temp += itoa(current_state++);
    return temp;
}
//william: for OpNode
Type *setCoercedType(Type *t1, Type *t2, ExprNode *arg1, ExprNode *arg2) {
    //need coerce here
    Type *genType;
    if (t1->tag() != t2->tag() && t1->isSubType(*t2)) {
        arg1->coercedType(t2);
        genType = t2;
    }
    else if (t1->tag() != t2->tag() && t2->isSubType(*t1)) {
        arg2->coercedType(t1);
        genType = t1;
    }
    else if (t1->tag() < t2->tag()) {
        arg1->coercedType(t2);
        genType = t2;
    } else {
        arg2->coercedType(t1);
        genType = t1;
    }
    return genType;
}

//william: for OpNode Relational and Arithmatic OP
bool isIntFloat(Type *t) {
    if (Type::isFloat(t->tag()) || Type::isInt(t->tag()))
        return true;
    if (t->tag() == Type::BYTE)
        return true;
    return false;
}

three_addr_ins *genLabel(string lab) {
    three_addr_ins *tmp = new three_addr_ins();
    tmp->arity = three_addr_ins::LABEL;
    strcpy(tmp->label, lab.c_str());
    return tmp;
}

three_addr_ins *genGotoLabel(string lab) {
    three_addr_ins *tmp = new three_addr_ins();
    tmp->arity = three_addr_ins::GOTOLABEL;
    strcpy(tmp->label, lab.c_str());
    return tmp;
}

three_addr_ins *genIfLabel(address* addr_e1, string opName, address* addr_e2, char* lab) {
    three_addr_ins *tmp = new three_addr_ins();    
    tmp->arity = three_addr_ins::IFLABEL;    
    tmp->oprand1 = addr_e1;
    tmp->oprand2 = addr_e2;
    tmp->op = opName;    
    strcpy(tmp->label, lab);
    return tmp;
}

three_addr_ins *genStateLabel(string state, string state_val, char* gotoLab) {
    address *addr1 = new address();
    address *addr2 = new address();
    addr1->sValue = state;
    addr1->atype = address::CONST_STR;
    addr2->sValue = state_val;
    addr2->atype = address::CONST_STR;

    return genIfLabel(addr1, "==", addr2, gotoLab);
}

three_addr_ins *genRuleLabel(string evenName, char* lab) {
    three_addr_ins *tmp = new three_addr_ins();
    address *addr1 = new address();
    addr1->sValue = "IN";
    addr1->atype = address::CONST_STR;
    address *addr2 = new address();
    addr2->sValue = evenName;
    addr2->atype = address::CONST_STR; //???
    //tmp->arity = three_addr_ins::RULELABEL;
    //tmp->oprand1 = addr;
    //strcpy(tmp->label, lab);
    //return tmp;

    return genIfLabel(addr1, "==", addr2, lab);
}

three_addr_ins *genUpdateStateLabel(string state_str, string op) {
    three_addr_ins *tmp = new three_addr_ins();
    address *addr1 = new address();
    address *addr2 = new address();
    addr1->sValue = curState;
    addr1->atype = address::CONST_STR; 
    addr2->sValue = state_str;
    addr2->atype = address::CONST_STR; 

    tmp->arity = 1;
    tmp->op = op;
    tmp->dest = addr1;
    tmp->oprand1 = addr2;
    return tmp;
}
bool isRelOp(int opcode) {
    if (opcode == OpNode::EQ || opcode == OpNode::GE || opcode == OpNode::LT ||
            opcode == OpNode::LE || opcode == OpNode::GT || opcode == OpNode::NE)
        return true;
    return false;
}


// ---- william end here -----
